feat(abstract-eth): add ERC20Votes delegateBySig EIP-712 helpers#8660
Open
feat(abstract-eth): add ERC20Votes delegateBySig EIP-712 helpers#8660
Conversation
Adds reusable EIP-712 builders for OpenZeppelin `ERC20Votes`-style `delegateBySig` so cold-custody clients can delegate voting power to a self-custody hot wallet without moving funds: - `buildErc20VotesDelegationTypedData` returns the canonical `Delegation(address delegatee,uint256 nonce,uint256 expiry)` typed data with a well-formed `EIP712Domain` block. - `encodeErc20VotesDelegationTypedDataDigest(Hex)` produces the v4 `\x19\x01 || hashStruct(domain) || hashStruct(message)` digest used by BitGo typed-data tx requests (`messageEncoded` / `typedDataEncoded`). - `encodeDelegateBySigCalldata` returns the ABI-encoded on-chain submission payload so any relayer can post the signature. - Ships a WLFI Ethereum mainnet domain helper as a reference template. Also: - Wires `MessageStandardType.EIP712` through `createTxRequestWithIntentForTypedDataSigning` / `IntentOptionsForTypedData` / `PopulatedIntentForTypedDataSigning` so WP can distinguish typed-data delegation messages from plain `signMessage` intents. - Adds a runnable example under `examples/ts/eth/push-erc20-votes-delegation-txrequest.ts` that pushes a delegation tx request to WP via `wallet.signTypedData(...)`. - Unit tests cover the domain/message hash, digest hex, and calldata. Ticket: CGD-842 Made-with: Cursor
|
@claude review this pr in 500 words |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a productized path for cold-custody governance participation via EIP-712
delegateBySigmeta-transactions. Cold wallet holders can now delegate votingpower to a self-custody hot wallet without moving funds or paying gas — BitGo
signs the EIP-712 typed data with the cold wallet's ETH MPC keys, and any relayer
can submit the
delegateBySig(delegatee, nonce, expiry, v, r, s)call on-chain.See ticket CGD-842 for context — this
is the BitGoJS half; WP companion changes ship separately in
BitGo/bitgo-microservices#58250.
What's included
New:
@bitgo/abstract-ethERC20Votes delegation helpers (modules/abstract-eth/src/lib/eip712/)buildErc20VotesDelegationTypedData({ domain, message })— canonical OZDelegation(address delegatee,uint256 nonce,uint256 expiry)payload withproper
EIP712Domainblock and normalized fields.encodeErc20VotesDelegationTypedDataDigest(Hex)— v4 digest(
\x19\x01 || hashStruct(domain) || hashStruct(message)) for BitGotyped-data tx requests (
messageEncoded/typedDataEncoded).encodeDelegateBySigCalldata({ delegatee, nonce, expiry, v, r, s })—ABI-encoded on-chain submission payload for any relayer.
wlfiEthereumMainnetDelegationDomain()— reference domain for the WLFIproxy at
0xda5e1988097297dcdc1f90d4dfe7909e847cbef6. The same pattern worksfor UNI, COMP, ARB, ENS, OP and every OZ-ERC20Votes token.
Wire
MessageStandardType.EIP712through the typed-data signing pathso WP can distinguish delegation messages from plain
signMessageintents androute them to the dedicated TAT Kafka topic rather than
sendQ:modules/sdk-core/src/bitgo/utils/tss/baseTypes.ts:IntentOptionsForTypedDataandPopulatedIntentForTypedDataSigningnowcarry an optional
messageStandardType.modules/sdk-core/src/bitgo/utils/tss/baseTSSUtils.ts: passesmessageStandardTypethroughcreateTxRequestBasewhen building the intentfor message signing.
modules/sdk-core/src/bitgo/wallet/wallet.ts:signTypedDataexplicitlysets
MessageStandardType.EIP712on the intent.Runnable example:
examples/ts/eth/push-erc20-votes-delegation-txrequest.tspushes a WLFI delegation tx request to WP via
wallet.signTypedData(...).Tests
modules/abstract-eth/test/unit/eip712/erc20VotesDelegation.ts:TypedDataUtils.eip712HashdelegateBySigcalldata matches the canonical ABI encodingTest plan
yarn test --scope @bitgo/abstract-eth(neweip712/erc20VotesDelegationsuite)yarn test --scope @bitgo/sdk-corecovering typed-data intent creation (createTxRequestWithIntentForTypedDataSigning)examples/ts/eth/push-erc20-votes-delegation-txrequest.tsagainst a staging ETH MPC cold wallet, verifying WP returns a tx request withmessages[0].messageStandardType === 'EIP712'andintent.intentType === 'signTypedStructuredData'typed-data-delegation-signing-requestKafka topic (notsendQ)Rollout
messageStandardTypefield is optional and existingsignMessageintents remain unchanged.References
ERC20VotesUpgradeable.delegateBySig: https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/token/ERC20/extensions/ERC20VotesUpgradeable.solMade with Cursor